package com.afdor.rws.event.driven.commons;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程相关工作类
 *
 * @author 悭梵
 * @date Created in 2018-12-05 16:38
 */
public final class ThreadUtils {

    public static ScheduledThreadPoolExecutor getScheduledThreadPool() {
        return SCHEDULED_THREAD_POOL;
    }

    /**
     * 计划任务线程池
     */
    private static final ScheduledThreadPoolExecutor SCHEDULED_THREAD_POOL = new ScheduledThreadPoolExecutor(5, new ThreadFactory() {
        /**
         * 线程计数器
         */
        private AtomicInteger threadIndex = new AtomicInteger(0);

        /**
         * 线程组
         */
        private ThreadGroup threadGroup = new ThreadGroup("event-bus") {
            {
                setDaemon(true);
                setMaxPriority(Thread.NORM_PRIORITY);
            }
        };

        private Thread.UncaughtExceptionHandler uncaughtExceptionHandler = new DefaultUncaughtExceptionHandler();

        @Override
        public Thread newThread(Runnable runnable) {
            Thread thread = new Thread(threadGroup, runnable, "thread-event-bus-" + threadIndex.getAndIncrement());
            thread.setDaemon(true);
            thread.setPriority(Thread.MIN_PRIORITY);
            thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
            return thread;
        }
    }, new ThreadPoolExecutor.CallerRunsPolicy());

    /**
     * 线程异常拦截输出
     */
    @Slf4j
    public static class DefaultUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

        @Override
        public void uncaughtException(Thread t, Throwable e) {
            log.error("thread " + t.getName() + " exception", e);
        }
    }

    public static String getStackMessage(Throwable e) {
        StringBuilder sb = new StringBuilder(5000);
        sb.append(e.getClass().getName());
        if (StringUtils.isNotBlank(e.getMessage())) {
            sb.append(": ").append(e.getMessage()).append("\n");
        }
        StackTraceElement[] stackArray = e.getStackTrace();
        for (int i = 0; i < stackArray.length; i++) {
            StackTraceElement element = stackArray[i];
            sb.append("\t").append(element.toString()).append("\n");
        }
        return sb.toString();
    }
}
